package com.zt.chatgpt.infrastructure.util;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.apache.commons.lang3.StringUtils;

import java.io.Writer;

/**
 * @author: zt
 * @Description: xml解析工具类
 * @create: 2024-05-12 22:00
 */

public class XmlUtil {

    /**
     * 获取一个配置了自定义XML输出格式的XStream实例。
     * 这个方法通过重写XppDriver的createWriter方法，以及PrettyPrintWriter的writeText方法，
     * 使得所有非数字的文本节点都被封装在CDATA段中，以避免XML特殊字符的问题。
     */
    public static XStream getMyXStream() {
        return new XStream(new XppDriver() {
            @Override
            public HierarchicalStreamWriter createWriter(Writer out) {
                return new PrettyPrintWriter(out) {
                    // 对所有xml节点都增加CDATA标记
                    boolean cData = true;

                    @Override
                    public void startNode(String name) {
                        super.startNode(name);
                    }

                    /**
                     * 对所有的文本内容采用CDATA格式输出
                     */
                    @Override
                    protected void writeText(QuickWriter writer, String text) {
                        if (cData && !StringUtils.isNumeric(text)) {
                            writer.write("<![CDATA[");
                            writer.write(text);
                            writer.write("]]>");
                        } else {
                            writer.write(text);
                        }
                    }
                };
            }
        });
    }

    /**
     * 将Java Bean转换为微信消息的XML格式字符串。
     *
     * @param object 需要转换为XML格式的Java Bean对象。
     * @return 转换后的XML格式字符串。如果转换失败或输入对象为空，则返回null。
     */
    public static String beanToXml(Object object) {
        XStream xStream = getMyXStream();
        xStream.alias("xml", object.getClass());
        xStream.processAnnotations(object.getClass());
        String xml = xStream.toXML(object);
        if (!StringUtils.isEmpty(xml)) {
            return xml;
        } else {
            return null;
        }
    }
    /**
     * 将XML字符串转换为指定类型的Bean对象。
     *
     * @param resultXml 待转换的XML字符串。
     * @param clazz 需要转换成的目标Bean对象的Class类型。
     * @return 转换后的Bean对象实例。
     * @param <T> 转换后的Bean对象的类型。
     */
    public static <T> T xmlToBean(String resultXml, Class clazz) {
        // XStream对象设置默认安全防护
        XStream stream = new XStream(new DomDriver());
        XStream.setupDefaultSecurity(stream);
        // 允许转换指定类型的Bean对象
        stream.allowTypes(new Class[]{clazz});
        //处理Bean对象的注解
        stream.processAnnotations(new Class[]{clazz});
        //设置XStream的模式为NO_REFERENCES，以避免循环引用
        stream.setMode(XStream.NO_REFERENCES);
        stream.alias("xml", clazz);
        return (T) stream.fromXML(resultXml);
    }
}
